from __future__ import absolute_import

import logging
import traceback
from datetime import datetime
from urllib.parse import urlparse
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import DisallowedHost
from django.utils.http import is_same_domain
from django.http import QueryDict
from django.middleware.csrf import _sanitize_token, _compare_masked_tokens,\
    REASON_NO_REFERER, REASON_MALFORMED_REFERER, \
    REASON_INSECURE_REFERER, REASON_BAD_REFERER, REASON_NO_CSRF_COOKIE, REASON_BAD_TOKEN, CsrfViewMiddleware

from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework import status


from huaweicloudsdkcore.auth.credentials import BasicCredentials
from huaweicloudsdkcore.http.http_config import HttpConfig
from huaweicloudsdkces.v2 import CesClient

from conf.conf import ces_ak, ces_sk, ces_project_id, ces_endpoint

logger = logging.getLogger(__name__)


def record_ip(func):
    def wrapper(obj, request, *args, **kwargs):
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            client_ip = request.META['HTTP_X_FORWARDED_FOR']
            client_ip = client_ip.split(",")[0]
        else:
            try:
                client_ip = request.META['REMOTE_ADDR']
            except Exception as e:
                client_ip = ''
                logger.error("failed to resolve client_ip, "
                             "exception： %s, %s", repr(e), traceback.format_exc())
                logger.error("Unknow IP access %s", request.META['PATH_INFO'])
        return func(obj, request, *args, **kwargs)

    return wrapper


# 为request请求鉴权
def auth_request(view_func):
    csrf_view_middleware = CsrfViewMiddleware()

    # 校验token是否正确
    def auth_safety_method(obj, request, *args, **kwargs):
        if request.method not in settings.UN_SAFETY_METHODS:
            if request.is_secure():
                referer = request.META.get('HTTP_REFERER')
                if referer is None:
                    csrf_view_middleware._reject(request, REASON_NO_REFERER)
                    return Response({'details': REASON_NO_REFERER}, status=status.HTTP_401_UNAUTHORIZED)

                referer = urlparse(referer)

                # Make sure we have a valid URL for Referer.
                if '' in (referer.scheme, referer.netloc):
                    csrf_view_middleware._reject(request, REASON_MALFORMED_REFERER)
                    return Response({'details': REASON_MALFORMED_REFERER}, status=status.HTTP_401_UNAUTHORIZED)

                # Ensure that our Referer is also secure.
                if referer.scheme != 'https':
                    csrf_view_middleware._reject(request, REASON_INSECURE_REFERER)
                    return Response({'details': REASON_INSECURE_REFERER}, status=status.HTTP_401_UNAUTHORIZED)

                # If there isn't a CSRF_COOKIE_DOMAIN, require an exact match
                # match on host:port. If not, obey the cookie rules (or those
                # for the session cookie, if CSRF_USE_SESSIONS).
                good_referer = (
                    settings.SESSION_COOKIE_DOMAIN
                    if settings.CSRF_USE_SESSIONS
                    else settings.CSRF_COOKIE_DOMAIN
                )
                if good_referer is not None:
                    server_port = request.get_port()
                    if server_port not in ('443', '80'):
                        good_referer = '%s:%s' % (good_referer, server_port)
                else:
                    try:
                        # request.get_host() includes the port.
                        good_referer = request.get_host()
                    except DisallowedHost:
                        pass

                # Create a list of all acceptable HTTP referers, including the
                # current host if it's permitted by ALLOWED_HOSTS.
                good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
                if good_referer is not None:
                    good_hosts.append(good_referer)

                if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
                    reason = REASON_BAD_REFERER % referer.geturl()
                    csrf_view_middleware._reject(request, reason)
                    return Response({'details': reason}, status=status.HTTP_401_UNAUTHORIZED)

            # Access csrf_token via self._get_token() as rotate_token() may
            # have been called by an authentication middleware during the
            # process_request() phase.
            csrf_token = csrf_view_middleware._get_token(request)
            if csrf_token is None:
                # No CSRF cookie. For POST requests, we insist on a CSRF cookie,
                # and in this way we can avoid all CSRF attacks, including login
                # CSRF.
                csrf_view_middleware._reject(request, REASON_NO_CSRF_COOKIE)
                return Response({'details': REASON_NO_CSRF_COOKIE}, status=status.HTTP_401_UNAUTHORIZED)

            # Check non-cookie token for match.
            request_csrf_token = ""
            if request.method == "POST":
                try:
                    request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
                except OSError:
                    pass
            if request_csrf_token == "":
                # Fall back to X-CSRFToken, to make things easier for AJAX,
                # and possible for PUT/DELETE.
                request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

            request_csrf_token = _sanitize_token(request_csrf_token)
            if not _compare_masked_tokens(request_csrf_token, csrf_token):
                csrf_view_middleware._reject(request, REASON_BAD_TOKEN)
                return Response({'details': REASON_BAD_TOKEN}, status=status.HTTP_401_UNAUTHORIZED)

        request.csrf_processing_done = True
        return view_func(obj, request, *args, **kwargs)

    return auth_safety_method


def get_parameter_dic(request):
    if not isinstance(request, Request):
        return {}

    query_params = request.query_params
    if isinstance(query_params, QueryDict):
        query_params = query_params.dict()
    result_data = request.data
    if isinstance(result_data, QueryDict):
        result_data = result_data.dict()

    if query_params != {}:
        return query_params
    else:
        return result_data


def scenario_conversion_main_scene(scenario_id):
    if scenario_id in ('follow_big_car', 'follow_and_stop'):
        value = "follow_car"
    elif scenario_id in ('cut_in-1', 'cut_in-2', 'overtake'):
        value = "cut_in"
    else:
        value = "confluence"
    return value


# save cache
def set_cache(value, key, timeout=10 * 60):
    cache.set(key, value, timeout)


# get cache
def get_cache(*keys):
    key = ""
    for t in keys:
        key.join(t)
    value = cache.get(key)
    return value


def fill_filter_data(params):
    all_keys_dict = {
        "__icontains": ["name", "car_id", "area", "tag", "data_type", "storage_type"],
        "__range": ["collect_time"]
    }
    filter_data = {"is_delete": 0}
    for key, values in all_keys_dict.items():
        for query_key in values:
            value = params.get(query_key, '')
            if value:
                if key == "__range":
                    dt_from = datetime.strptime(value.split("-")[0], "%Y/%m/%d %H:%M:%S")
                    # 查询的时候默认date_to+86399(当天的23:59:59)
                    dt_to = datetime.strptime(value.split("-")[1], '%Y/%m/%d %H:%M:%S')
                    filter_data[query_key + key] = (dt_from, dt_to)
                else:
                    filter_data[query_key + key] = value
    return filter_data


def set_header(headers, storage_class):
    if storage_class == 0:
        headers.storageClass = 'STANDARD'
    elif storage_class == 1:
        headers.storageClass = 'WARM'
    elif storage_class == 2:
        headers.storageClass = 'COLD'


def get_ces_client(ak, sk, endpoint, project_id):
    config = HttpConfig.get_default_config()
    config.ignore_ssl_verification = True
    credentials = BasicCredentials(ak, sk, project_id)
    new_ces_client = CesClient.new_builder() \
        .with_http_config(config) \
        .with_credentials(credentials) \
        .with_endpoint(endpoint) \
        .build()
    return new_ces_client


ces_client = get_ces_client(ces_ak, ces_sk, ces_endpoint, ces_project_id)
